package org.wsiz.vro.domain;

import static javax.persistence.CascadeType.PERSIST;
import static javax.persistence.FetchType.LAZY;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.Version;
import javax.xml.bind.annotation.XmlTransient;

import org.apache.log4j.Logger;
import org.springframework.data.domain.Persistable;

import com.google.common.base.Objects;

/**
 * @author "Tomasz Marciniak"
 */
@Entity
@Table(name = "rental")
public class Rental implements Persistable<Integer> {
	private static final long serialVersionUID = 1L;

	@SuppressWarnings("unused")
	private static final Logger log = Logger.getLogger(Rental.class);

	private Integer id;
	private Integer accountId;
	private Double totalPrice;

	private Account account;
	private List<Inventory> inventories = new ArrayList<Inventory>();

	public Rental() {
	}

	public Rental(Integer primaryKey) {
		setId(primaryKey);
	}

	@Override
	@Transient
	@XmlTransient
	public boolean isNew() {
		return getId() == null;
	}

	@Column(nullable = false, unique = true, precision = 10)
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Id
	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	@Column(name = "account_id", length = 32, insertable = false, updatable = false)
	public Integer getAccountId() {
		return accountId;
	}

	private void setAccountId(Integer accountId) {
		this.accountId = accountId;
	}

	@Column(name = "total_price", precision = 10)
	@Version
	public Double getTotalPrice() {
		return totalPrice;
	}

	public void setTotalPrice(Double totalPrice) {
		this.totalPrice = totalPrice;
	}

	@JoinColumn(name = "account_id")
	@ManyToOne(cascade = PERSIST, fetch = LAZY)
	public Account getAccount() {
		return account;
	}

	/**
	 * Set the account without adding this Book instance on the passed account
	 * If you want to preserve referential integrity we recommend to use instead
	 * the corresponding adder method provided by {@link Account}
	 */
	public void setAccount(Account account) {
		this.account = account;

		// We set the foreign key property so it can be used by Hibernate search
		// by Example facility.
		if (account != null) {
			setAccountId(account.getId());
		} else {
			setAccountId(null);
		}
	}

	/**
	 * Returns the inventories list.
	 */
	@JoinTable(name = "account_inventory", joinColumns = @JoinColumn(name = "account_id"), inverseJoinColumns = @JoinColumn(name = "inventory_id"))
	@ManyToMany(cascade = PERSIST)
	public List<Inventory> getInventories() {
		return inventories;
	}

	/**
	 * Set the inventories list.
	 * <p>
	 * It is recommended to use the helper method
	 * {@link #addInventory(Inventory)} / {@link #removeInventory(Inventory)} if
	 * you want to preserve referential integrity at the object level.
	 * 
	 * @param inventories
	 *            the list of Inventory
	 */
	public void setInventories(List<Inventory> inventories) {
		this.inventories = inventories;
	}

	/**
	 * Helper method to add the passed {@link Inventory} to the inventories
	 * list.
	 */
	public boolean addInventory(Inventory inventory) {
		return getInventories().add(inventory);
	}

	/**
	 * Helper method to remove the passed {@link Inventory} from the inventories
	 * list.
	 */
	public boolean removeInventory(Inventory inventory) {
		return getInventories().remove(inventory);
	}

	/**
	 * Helper method to determine if the passed {@link Inventory} is present in
	 * the inventories list.
	 */
	public boolean containsInventory(Inventory inventory) {
		return getInventories() != null && getInventories().contains(inventory);
	}

	/**
	 * Set the default values.
	 */
	public void initDefaultValues() {
	}

	@Override
	public boolean equals(Object other) {
		return this == other
				|| (other instanceof Rental && hashCode() == other.hashCode());
	}

	private PersistableHashBuilder persistableHashBuilder = new PersistableHashBuilder();

	@Override
	public int hashCode() {
		return persistableHashBuilder.hash(this);
	}

	/**
	 * Construct a readable string representation for this {@link Rental}
	 * instance.
	 */
	@Override
	public String toString() {
		return Objects.toStringHelper(this) //
				.add("id", getId()) //
				.add("totalPrice", getTotalPrice()) //
				.toString();
	}
}